﻿namespace Contoso.ActiveDirectory {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.DirectoryServices;
    using System.Globalization;
    using System.Linq;
    using System.Text;
    using System.Threading;
    #endregion

    [Serializable]
    public class ExchangeActiveSyncDevice : ADBaseObjectProperties, IExchangeActiveSyncDevice {

        #region Members
        private static readonly string ActiveSyncDevicesTag = "CN=ExchangeActiveSyncDevices,";
        public static readonly string ObjectCategoryShortName = "msExchActiveSyncDevice";

        public MSExchDeviceAccessState MSExchDeviceAccessState { get { return msExchDeviceAccessState; } }
        private MSExchDeviceAccessState msExchDeviceAccessState;

        public string MSExchDeviceEASVersion { get; private set; }
        public string MSExchDeviceFriendlyName { get; private set; }
        public string MSExchDeviceID { get; private set; }
        public string MSExchDeviceIMEI { get; private set; }
        public string MSExchDeviceMobileOperator { get; private set; }
        public string MSExchDeviceModel { get; private set; }
        public string MSExchDeviceOS { get; private set; }
        public string MSExchDeviceOSLanguage { get; private set; }
        public string MSExchDeviceTelephoneNumber { get; private set; }
        public string MSExchDeviceType { get; private set; }
        public string MSExchDeviceUserAgent { get; private set; }
        public string MSExchUserDisplayName { get; private set; }
        public DateTime? MSExchFirstSyncTime {
            get {
                if (msExchFirstSyncTime != DateTime.MinValue) {
                    return msExchFirstSyncTime;
                }
                else {
                    return null;
                }
            }
        }
        private DateTime msExchFirstSyncTime;
        public DateTime? MSExchLastUpdateTime {
            get {
                if (msExchLastUpdateTime != DateTime.MinValue) {
                    return msExchLastUpdateTime;
                }
                else {
                    return null;
                }
            }
        }
        private DateTime msExchLastUpdateTime;
        public long MSExchVersion { get; private set; }

        /// <summary>
        /// The distinguished name of the UserAccount that owns this ActiveSync device
        /// </summary>
        public string OwnerMailboxDN {
            get {
                string ownerMailboxDN = string.Empty;
                // CN=iPhone§ApplF2ABCDE2ABCD,CN=ExchangeActiveSyncDevices,CN=xxxxxxx,OU=Users,OU=HQ,DC=contoso,DC=com
                if (!string.IsNullOrWhiteSpace(this.DN)) {
                    if (this.DN.IndexOf(ActiveSyncDevicesTag, StringComparison.OrdinalIgnoreCase) > -1) {
                        ownerMailboxDN = this.DN.Substring(this.DN.IndexOf(ActiveSyncDevicesTag, StringComparison.OrdinalIgnoreCase));
                        if (ownerMailboxDN.Length > ActiveSyncDevicesTag.Length) {
                            ownerMailboxDN = ownerMailboxDN.Substring(ActiveSyncDevicesTag.Length);
                        }
                    }
                }

                return ownerMailboxDN;
            }

        }
        #endregion

        #region Constructor
        public ExchangeActiveSyncDevice() {
            this.Initialize();
        }

        public ExchangeActiveSyncDevice(DirectoryEntry directoryEntry, bool destroyInputObject = true)
            : base(directoryEntry, destroyInputObject) {
            if (this.GetType().Name == typeof(ExchangeActiveSyncDevice).Name) {
                this.Attributes = null;
            }
        }

        public ExchangeActiveSyncDevice(SearchResult result, bool destroyInputObject = true)
            : base(result, destroyInputObject) {
            if (this.GetType().Name == typeof(ExchangeActiveSyncDevice).Name) {
                this.Attributes = null;
            }
        }

        public ExchangeActiveSyncDevice(List<string> ldifOutput)
            : base(ldifOutput) {
            if (this.GetType().Name == typeof(ExchangeActiveSyncDevice).Name) {
                this.Attributes = null;
            }
        }
        #endregion

        #region Methods
        protected override void Initialize() {
            base.Initialize();

            msExchDeviceAccessState = MSExchDeviceAccessState.Undefined;
            this.MSExchDeviceEASVersion = string.Empty;
            this.MSExchDeviceFriendlyName = string.Empty;
            this.MSExchDeviceID = string.Empty;
            this.MSExchDeviceIMEI = string.Empty;
            this.MSExchDeviceMobileOperator = string.Empty;
            this.MSExchDeviceModel = string.Empty;
            this.MSExchDeviceOS = string.Empty;
            this.MSExchDeviceOSLanguage = string.Empty;
            this.MSExchDeviceTelephoneNumber = string.Empty;
            this.MSExchDeviceType = string.Empty;
            this.MSExchDeviceUserAgent = string.Empty;
            this.MSExchUserDisplayName = string.Empty;
        }

        protected override void ProcessResults() {

            try {
                base.ProcessResults();

                if (this.Attributes.ContainsKey("msExchDeviceAccessState")) {
                    Enum.TryParse<MSExchDeviceAccessState>(this.Attributes["msExchDeviceAccessState"][0].ToString(), ignoreCase: true, result: out msExchDeviceAccessState);
                }

                if (this.Attributes.ContainsKey("msExchDeviceEASVersion")) {
                    this.MSExchDeviceEASVersion = this.Attributes["msExchDeviceEASVersion"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceFriendlyName")) {
                    this.MSExchDeviceFriendlyName = this.Attributes["msExchDeviceFriendlyName"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceID")) {
                    this.MSExchDeviceID = this.Attributes["msExchDeviceID"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceIMEI")) {
                    this.MSExchDeviceIMEI = this.Attributes["msExchDeviceIMEI"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceMobileOperator")) {
                    this.MSExchDeviceMobileOperator = this.Attributes["msExchDeviceMobileOperator"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceModel")) {
                    this.MSExchDeviceModel = this.Attributes["msExchDeviceModel"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceOS")) {
                    this.MSExchDeviceOS = this.Attributes["msExchDeviceOS"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceOSLanguage")) {
                    this.MSExchDeviceOSLanguage = this.Attributes["msExchDeviceOSLanguage"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceTelephoneNumber")) {
                    this.MSExchDeviceTelephoneNumber = this.Attributes["msExchDeviceTelephoneNumber"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceType")) {
                    this.MSExchDeviceType = this.Attributes["msExchDeviceType"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceUserAgent")) {
                    this.MSExchDeviceUserAgent = this.Attributes["msExchDeviceUserAgent"][0].ToString();
                }
                if (this.Attributes.ContainsKey("msExchDeviceType")) {
                    this.MSExchDeviceType = this.Attributes["msExchDeviceType"][0].ToString();
                }

                var dateTimeFormat = "yyyyMMddHHmmss";
                if (this.Attributes.ContainsKey("msExchFirstSyncTime")) {
                    if (!DateTime.TryParse(this.Attributes["msExchFirstSyncTime"][0].ToString(), out msExchFirstSyncTime)) {
                        if (this.Attributes["msExchFirstSyncTime"][0].ToString().Length >= dateTimeFormat.Length) {
                            if (!DateTime.TryParseExact(this.Attributes["msExchFirstSyncTime"][0].ToString().Substring(0, dateTimeFormat.Length), "yyyyMMddHHmmss",
                                CultureInfo.InvariantCulture,
                                DateTimeStyles.AssumeUniversal, out msExchFirstSyncTime)) {
                                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} warning: unable to parse datetime for msExchFirstSyncTime: {3}",
                                    DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId,
                                    CustomExtensions.CurrentMethodName(), this.Attributes["msExchFirstSyncTime"][0].ToString()));
                            }
                        }
                    }
                }
                if (this.Attributes.ContainsKey("msExchLastUpdateTime")) {
                    if (!DateTime.TryParse(this.Attributes["msExchLastUpdateTime"][0].ToString(), out msExchLastUpdateTime)) {
                        if (this.Attributes["msExchLastUpdateTime"][0].ToString().Length >= dateTimeFormat.Length) {
                            if (!DateTime.TryParseExact(this.Attributes["msExchLastUpdateTime"][0].ToString().Substring(0, dateTimeFormat.Length), "yyyyMMddHHmmss",
                                CultureInfo.InvariantCulture,
                                DateTimeStyles.AssumeUniversal, out msExchLastUpdateTime)) {
                                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} warning: unable to parse datetime for msExchLastUpdateTime: {3}",
                                    DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId,
                                    CustomExtensions.CurrentMethodName(), this.Attributes["msExchLastUpdateTime"][0].ToString()));
                            }
                        }
                    }
                }
                if (this.Attributes.ContainsKey("msExchVersion")) {
                    this.MSExchVersion = Convert.ToInt64(this.Attributes["MSExchVersion"][0]);
                }

                this.IsValid = !string.IsNullOrWhiteSpace(this.DN)
                    && this.ObjectClass.Any(x => string.Equals(x, ObjectCategoryShortName, StringComparison.OrdinalIgnoreCase));
            }
            catch (Exception e) {
                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} Error: {3}", DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId, CustomExtensions.CurrentMethodName(), e.VerboseExceptionString()));
                throw;
            }
        }
        #endregion
    }
}
